package day17.edu;
// Created: 17/09/2025, ChangJiang Ru

import java.util.*;
import java.util.stream.Collectors;

public class DouDiZhuGame {

    // 扑克牌类
    class Card {
        private String suit; // 花色
        private String rank; // 点数
        private int weight;  // 权重（用于比较大小）

        public Card(String suit, String rank, int weight) {
            this.suit = suit;
            this.rank = rank;
            this.weight = weight;
        }

        public String getSuit() { return suit; }
        public String getRank() { return rank; }
        public int getWeight() { return weight; }

        @Override
        public String toString() {
            return suit + rank;
        }
    }

    // 玩家类
    class Player {
        private String name;
        private List<Card> handCards;
        private boolean isLandlord; // 是否是地主

        public Player(String name) {
            this.name = name;
            this.handCards = new ArrayList<>();
            this.isLandlord = false;
        }

        public String getName() { return name; }
        public List<Card> getHandCards() { return handCards; }
        public boolean isLandlord() { return isLandlord; }
        public void setLandlord(boolean isLandlord) { this.isLandlord = isLandlord; }

        // 添加手牌
        public void addCard(Card card) {
            handCards.add(card);
        }

        // 排序手牌
        public void sortHandCards() {
            handCards.sort((c1, c2) -> c2.getWeight() - c1.getWeight());
        }

        // 出牌
        public List<Card> playCards(int[] indices) {
            List<Card> played = new ArrayList<>();
            Arrays.sort(indices);

            for (int i = indices.length - 1; i >= 0; i--) {
                if (indices[i] >= 0 && indices[i] < handCards.size()) {
                    played.add(handCards.remove(indices[i]));
                }
            }

            return played;
        }

        // 显示手牌
        public void showHandCards() {
            System.out.print(name + "的手牌(" + handCards.size() + "张): ");
            for (int i = 0; i < handCards.size(); i++) {
                System.out.print("[" + i + "]" + handCards.get(i) + " ");
                if ((i + 1) % 10 == 0) System.out.println();
            }
            System.out.println();
        }

        // 是否有牌可出（简化判断）
        public boolean hasValidCardsToPlay(List<Card> lastCards) {
            if (lastCards.isEmpty()) return true;

            // 如果有炸弹或火箭，总是可以出
            for (int i = 0; i < handCards.size() - 3; i++) {
                if (handCards.get(i).getWeight() == handCards.get(i + 1).getWeight() &&
                        handCards.get(i).getWeight() == handCards.get(i + 2).getWeight() &&
                        handCards.get(i).getWeight() == handCards.get(i + 3).getWeight()) {
                    return true;
                }
            }

            // 检查是否有火箭
            boolean hasSmallJoker = false, hasBigJoker = false;
            for (Card card : handCards) {
                if (card.getWeight() == 16) hasSmallJoker = true;
                if (card.getWeight() == 17) hasBigJoker = true;
            }
            if (hasSmallJoker && hasBigJoker) return true;

            return false;
        }
    }

    // 牌型判断类
    class CardTypeChecker {
        public String checkCardType(List<Card> cards) {
            if (cards == null || cards.isEmpty()) return "空";
            if (isSingle(cards)) return "单张";
            if (isPair(cards)) return "对子";
            if (isTriple(cards)) return "三张";
            if (isBomb(cards)) return "炸弹";
            if (isTripleWithSingle(cards)) return "三带一";
            if (isTripleWithPair(cards)) return "三带对";
            if (isStraight(cards)) return "顺子";
            if (isConsecutivePairs(cards)) return "连对";
            if (isAirplane(cards)) return "飞机";
            if (isAirplaneWithWings(cards)) return "飞机带翅膀";
            if (isRocket(cards)) return "火箭";
            return "无效牌型";
        }

        private boolean isSingle(List<Card> cards) {
            return cards.size() == 1;
        }

        private boolean isPair(List<Card> cards) {
            return cards.size() == 2 && cards.get(0).getWeight() == cards.get(1).getWeight();
        }

        private boolean isTriple(List<Card> cards) {
            return cards.size() == 3 &&
                    cards.get(0).getWeight() == cards.get(1).getWeight() &&
                    cards.get(1).getWeight() == cards.get(2).getWeight();
        }

        private boolean isBomb(List<Card> cards) {
            if (cards.size() != 4) return false;
            int weight = cards.get(0).getWeight();
            return cards.stream().allMatch(c -> c.getWeight() == weight);
        }

        private boolean isRocket(List<Card> cards) {
            if (cards.size() != 2) return false;
            return (cards.get(0).getWeight() == 16 && cards.get(1).getWeight() == 17) ||
                    (cards.get(0).getWeight() == 17 && cards.get(1).getWeight() == 16);
        }

        private boolean isTripleWithSingle(List<Card> cards) {
            if (cards.size() != 4) return false;
            Map<Integer, Integer> weightCount = new HashMap<>();
            for (Card card : cards) {
                weightCount.put(card.getWeight(), weightCount.getOrDefault(card.getWeight(), 0) + 1);
            }
            return weightCount.containsValue(3) && weightCount.containsValue(1);
        }

        private boolean isTripleWithPair(List<Card> cards) {
            if (cards.size() != 5) return false;
            Map<Integer, Integer> weightCount = new HashMap<>();
            for (Card card : cards) {
                weightCount.put(card.getWeight(), weightCount.getOrDefault(card.getWeight(), 0) + 1);
            }
            return weightCount.containsValue(3) && weightCount.containsValue(2);
        }

        // 其他牌型判断方法（简化实现）
        private boolean isStraight(List<Card> cards) {
            if (cards.size() < 5) return false;
            List<Integer> weights = cards.stream()
                    .map(Card::getWeight)
                    .distinct()
                    .sorted()
                    .collect(Collectors.toList());

            // 检查是否是连续的数字（2和王不能参与顺子）
            for (int i = 0; i < weights.size() - 1; i++) {
                if (weights.get(i) >= 13 || weights.get(i + 1) - weights.get(i) != 1) {
                    return false;
                }
            }
            return true;
        }

        private boolean isConsecutivePairs(List<Card> cards) {
            return false; // 简化实现
        }

        private boolean isAirplane(List<Card> cards) {
            return false; // 简化实现
        }

        private boolean isAirplaneWithWings(List<Card> cards) {
            return false; // 简化实现
        }

        // 比较牌型大小
        public boolean canBeat(List<Card> currentCards, List<Card> lastCards) {
            String currentType = checkCardType(currentCards);
            String lastType = checkCardType(lastCards);

            // 火箭可以打任何牌
            if (currentType.equals("火箭")) return true;

            // 炸弹可以打非火箭的任何牌
            if (currentType.equals("炸弹") && !lastType.equals("火箭")) {
                return true;
            }

            // 同类型牌比较
            if (currentType.equals(lastType) && currentCards.size() == lastCards.size()) {
                return currentCards.get(0).getWeight() > lastCards.get(0).getWeight();
            }

            return false;
        }
    }

    private List<Card> deck; // 牌堆
    private List<Player> players; // 玩家列表
    private Player landlord; // 地主
    private List<Card> lastPlayedCards; // 上一轮出的牌
    private Player lastPlayer; // 上一轮出牌的玩家
    private CardTypeChecker cardTypeChecker; // 牌型检查器
    private List<Card> bottomCards; // 底牌

    public DouDiZhuGame() {
        initializeDeck();
        players = Arrays.asList(new Player("玩家"), new Player("电脑1"), new Player("电脑2"));
        lastPlayedCards = new ArrayList<>();
        cardTypeChecker = new CardTypeChecker();
        bottomCards = new ArrayList<>();
    }

    // 初始化牌堆
    private void initializeDeck() {
        deck = new ArrayList<>();
        String[] suits = {"♠", "♥", "♦", "♣"};
        String[] ranks = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
        int[] weights = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};

        // 添加普通牌
        for (int i = 0; i < ranks.length; i++) {
            for (String suit : suits) {
                deck.add(new Card(suit, ranks[i], weights[i]));
            }
        }

        // 添加大小王
        deck.add(new Card("", "小王", 16));
        deck.add(new Card("", "大王", 17));
    }

    // 洗牌
    private void shuffleDeck() {
        Collections.shuffle(deck);
    }

    // 发牌
    private void dealCards() {
        shuffleDeck();

        // 发牌给三个玩家
        for (int i = 0; i < 51; i++) {
            players.get(i % 3).addCard(deck.get(i));
        }

        // 剩下的三张作为底牌
        bottomCards = new ArrayList<>(deck.subList(51, 54));
        System.out.print("底牌: ");
        bottomCards.forEach(card -> System.out.print(card + " "));
        System.out.println();

        // 排序手牌
        players.forEach(Player::sortHandCards);
    }

    // 叫地主
    private void bidForLandlord() {
        Scanner scanner = new Scanner(System.in);
        Random random = new Random();

        System.out.println("\n=== 叫地主环节 ===");

        // 简单模拟叫地主过程
        for (int i = 0; i < players.size(); i++) {
            Player player = players.get(i);

            if (player.getName().equals("玩家")) {
                // 玩家叫地主
                System.out.print("是否叫地主? (y/n): ");
                String input = scanner.nextLine();
                if (input.equalsIgnoreCase("y")) {
                    landlord = player;
                    player.setLandlord(true);
                    // 地主获得底牌
                    for (Card card : bottomCards) {
                        player.addCard(card);
                    }
                    player.sortHandCards();
                    System.out.println("你成为地主! 获得底牌");
                    break;
                }
            } else {
                // AI叫地主
                boolean bid = random.nextBoolean();
                System.out.println(player.getName() + (bid ? "叫地主" : "不叫"));
                if (bid) {
                    landlord = player;
                    player.setLandlord(true);
                    // 地主获得底牌
                    for (Card card : bottomCards) {
                        player.addCard(card);
                    }
                    player.sortHandCards();
                    System.out.println(player.getName() + "成为地主!");
                    break;
                }
            }
        }

        // 如果没人叫地主，随机选择
        if (landlord == null) {
            landlord = players.get(random.nextInt(3));
            landlord.setLandlord(true);
            // 地主获得底牌
            for (Card card : bottomCards) {
                landlord.addCard(card);
            }
            landlord.sortHandCards();
            System.out.println("随机选择" + landlord.getName() + "为地主!");
        }

        System.out.println("地主是: " + landlord.getName());
    }

    // 开始游戏
    public void startGame() {
        System.out.println("=== 斗地主游戏开始 ===");

        // 发牌
        dealCards();

        // 显示所有玩家手牌数量
        for (Player player : players) {
            System.out.println(player.getName() + "有 " + player.getHandCards().size() + " 张牌");
        }

        // 显示玩家手牌
        players.get(0).showHandCards();

        // 叫地主
        bidForLandlord();

        // 显示地主手牌
        if (landlord.getName().equals("玩家")) {
            System.out.println("你的手牌（作为地主）:");
            landlord.showHandCards();
        }

        // 游戏主循环
        playRound();
    }

    // 游戏回合
    private void playRound() {
        Scanner scanner = new Scanner(System.in);
        int currentPlayerIndex = players.indexOf(landlord);
        int consecutivePasses = 0; // 连续跳过的次数

        System.out.println("\n=== 游戏开始 ===");

        while (!isGameOver()) {
            Player currentPlayer = players.get(currentPlayerIndex);

            System.out.println("\n=== " + currentPlayer.getName() + "的回合 ===");

            if (currentPlayer.getName().equals("玩家")) {
                // 玩家回合
                currentPlayer.showHandCards();

                if (lastPlayedCards.isEmpty() || lastPlayer == currentPlayer) {
                    System.out.println("请出牌 (输入牌索引，用空格分隔): ");
                } else {
                    System.out.println("上家出牌: " + lastPlayedCards + " [" +
                            cardTypeChecker.checkCardType(lastPlayedCards) + "]");
                    System.out.println("请出牌 (输入牌索引，用空格分隔，输入-1跳过): ");
                }

                String input = scanner.nextLine();
                if (input.trim().equals("-1")) {
                    // 跳过
                    System.out.println("你选择跳过");
                    consecutivePasses++;
                    currentPlayerIndex = (currentPlayerIndex + 1) % 3;
                    continue;
                }

                try {
                    String[] indicesStr = input.split(" ");
                    int[] indices = new int[indicesStr.length];
                    for (int i = 0; i < indicesStr.length; i++) {
                        indices[i] = Integer.parseInt(indicesStr[i]);
                    }

                    List<Card> playedCards = currentPlayer.playCards(indices);
                    String cardType = cardTypeChecker.checkCardType(playedCards);

                    if (cardType.equals("无效牌型")) {
                        System.out.println("无效牌型，请重新出牌");
                        // 把牌加回去
                        currentPlayer.getHandCards().addAll(playedCards);
                        currentPlayer.sortHandCards();
                        continue;
                    }

                    // 检查是否能压过上家的牌
                    if (!lastPlayedCards.isEmpty() && lastPlayer != currentPlayer) {
                        if (!cardTypeChecker.canBeat(playedCards, lastPlayedCards)) {
                            System.out.println("不能压过上家的牌，请重新出牌");
                            // 把牌加回去
                            currentPlayer.getHandCards().addAll(playedCards);
                            currentPlayer.sortHandCards();
                            continue;
                        }
                    }

                    System.out.println("你出了: " + playedCards + " [" + cardType + "]");
                    lastPlayedCards = playedCards;
                    lastPlayer = currentPlayer;
                    consecutivePasses = 0;

                } catch (Exception e) {
                    System.out.println("输入错误，请重新出牌");
                    continue;
                }
            } else {
                // AI回合
                // 简单AI逻辑
                List<Card> aiPlayedCards = simpleAI(currentPlayer);

                if (aiPlayedCards.isEmpty()) {
                    System.out.println(currentPlayer.getName() + "选择跳过");
                    consecutivePasses++;
                } else {
                    String cardType = cardTypeChecker.checkCardType(aiPlayedCards);
                    System.out.println(currentPlayer.getName() + "出了: " + aiPlayedCards + " [" + cardType + "]");
                    lastPlayedCards = aiPlayedCards;
                    lastPlayer = currentPlayer;
                    consecutivePasses = 0;
                }
            }

            // 如果连续两个玩家跳过，清空上一轮出的牌
            if (consecutivePasses >= 2) {
                lastPlayedCards.clear();
                lastPlayer = null;
                consecutivePasses = 0;
                System.out.println("新一轮开始，可以出任意牌型");
            }

            // 切换到下一个玩家
            currentPlayerIndex = (currentPlayerIndex + 1) % 3;

            // 检查游戏是否结束
            if (isGameOver()) {
                break;
            }
        }

        // 游戏结束
        endGame();
    }

    // 简单AI逻辑
    private List<Card> simpleAI(Player aiPlayer) {
        List<Card> handCards = aiPlayer.getHandCards();
        if (handCards.isEmpty()) return new ArrayList<>();

        // 如果是第一个出牌或者上家是自己，出最小的单张牌
        if (lastPlayedCards.isEmpty() || lastPlayer == aiPlayer) {
            List<Card> played = new ArrayList<>();
            played.add(handCards.remove(handCards.size() - 1)); // 出最小的牌
            return played;
        }

        // 尝试出能压过上家的牌
        for (int i = handCards.size() - 1; i >= 0; i--) {
            List<Card> testCards = new ArrayList<>();
            testCards.add(handCards.get(i));

            if (cardTypeChecker.checkCardType(testCards).equals("单张") &&
                    handCards.get(i).getWeight() > lastPlayedCards.get(0).getWeight()) {
                return Arrays.asList(handCards.remove(i));
            }
        }

        // 没有能压过的牌，跳过
        return new ArrayList<>();
    }

    // 检查游戏是否结束
    private boolean isGameOver() {
        return players.stream().anyMatch(p -> p.getHandCards().isEmpty());
    }

    // 游戏结束
    private void endGame() {
        Player winner = players.stream()
                .filter(p -> p.getHandCards().isEmpty())
                .findFirst()
                .orElse(null);

        if (winner != null) {
            System.out.println("\n=== 游戏结束 ===");
            System.out.println(winner.getName() + "获胜!");

            if (winner.isLandlord()) {
                System.out.println("地主胜利!");
            } else {
                System.out.println("农民胜利!");
            }

            // 显示所有玩家剩余手牌
            System.out.println("\n剩余手牌:");
            for (Player player : players) {
                if (!player.getHandCards().isEmpty()) {
                    System.out.print(player.getName() + ": ");
                    player.getHandCards().forEach(card -> System.out.print(card + " "));
                    System.out.println();
                }
            }
        }
    }

    // 主方法
    public static void main(String[] args) {
        DouDiZhuGame game = new DouDiZhuGame();
        game.startGame();
    }
}